#pragma once
#include <SimpleDef.h>
#include <Synchronization/SpinLock.h>
/*
@brief Arena 描述符，每个 Arena 严格对应于一张虚拟页
@note 只有 wGranularity 为大于等于 16 且为 2 的整数次幂时（除非大于 4096），才表示指向有效的 Arena。
wGranularity 还可取 ARENA_NONE 和 ARENA_MORE，分别代表不指向任何内容以及指向另一张描述符表。
*/
typedef struct __ArenaDescriptor
{
    WORD wGranularity; /* 基本分配单元大小，必须大于等于 16 且为 2 的整数次幂 */
    WORD wAvailableUnits; /* 对于 Small Arena，指示 Arena 中可用的单元数量；对于 Big Arena，此项存放位图 */
    LPVOID lpArena; /* 指向 Arena 的指针 */
} ArenaDescriptor, *LPArenaDescriptor, *LPArenaDescriptorTable, *LPHeap;

#define ARENA_NONE (0) /* wszUnit 为此值表示当前描述符不指向任何内容 */
#define ARENA_MORE (1) /* wszUnit 为此值表示当前描述符指向描述符表 */

/* 128 B 及以下属于 Small Arena，位图至少占用一个单元，下面列举的是位图实际大小 */
#define ARENA16_BITMAP_SIZE (32) /* 刚好需要 32 B 位图 */
#define ARENA32_BITMAP_SIZE (16) /* 16 B 位图 */
#define ARENA64_BITMAP_SIZE (8) /* 8 B 位图 */
#define ARENA128_BITMAP_SIZE (4) /* 4 B 位图 */
/* 256 B 及以上属于 Big Arena，位图恰好能够被 wAvailableUnits 容纳 */

/*
@brief 获取不同单位的 Arena 对应的位图大小
@param UNIT_SIZE_IN_BYTES 单位大小，以字节为单位
@return Arena 位图大小，以 DWORD 为单位，不足 1 个 DWORD 的情况返回 0
@note 对于 Arena 大于等于 256 B 的情况，需要将 ArenaDescriptor 中的 wAvailableUnits 字段存放在 DWORD 变量中调用
    AquireAvailableBit，然后视情况更新 wAvailableUnits 字段
*/
#define ARENA_BITMAP_SIZE_IN_DWORD(UNIT_SIZE_IN_BYTES) \
(\
    UNIT_SIZE_IN_BYTES == 16 ? ARENA16_BITMAP_SIZE / sizeof(DWORD) : \
    UNIT_SIZE_IN_BYTES == 32 ? ARENA32_BITMAP_SIZE / sizeof(DWORD): \
    UNIT_SIZE_IN_BYTES == 64 ? ARENA64_BITMAP_SIZE / sizeof(DWORD):\
    UNIT_SIZE_IN_BYTES == 128 ? ARENA128_BITMAP_SIZE / sizeof(DWORD):\
    UNIT_SIZE_IN_BYTES == 256 ? 2 / sizeof(DWORD):\
    1 /sizeof(DWORD) /* 256 B 以上单位的 Arena 位图需要单独处理，按照 DWORD 对齐后使用 AquireAvailableBit */ \
)


#define HEAP_INITIALIZE_SUCCESS (0)
#define HEAP_INITIALIZE_INVALID_PARAM (1)
#define HEAP_INITIALIZE_FAIL (2)

BOOL InitializeArenaForUser(LPArenaDescriptor lpArenaDescriptor);
BOOL InitializeArenaForKernel(LPArenaDescriptor lpArenaDescriptor);
LPVOID HeapAllocate(LPArenaDescriptorTable lpHeap, DWORD dwFlags, DWORD dwBytes);
#define HEAP_ZERO_MEMORY (8) /* 初始化堆 */
DWORD HeapFree(LPHeap lpHeap, LPVOID lpAddress);

#define InitializeArena(lpArenaDescriptor) \
    if ((DWORD)(lpArenaDescriptor) < 0xC0000000) InitializeArenaForUser(lpArenaDescriptor); \
    else InitializeArenaForKernel(lpArenaDescriptor);
